package com.such.kit.datacast;

import java.io.UnsupportedEncodingException;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.such.kit.Callable;
import com.such.kit.Logger;
import com.such.kit.cache.CacheCommons;
import com.such.kit.string.StringCommons;
import com.such.kit.validate.ValidateCommons;
import com.such.kit.validate.ValidateDataType;

/**
 * @作者 SUCH
 * @日期 2017-2-17 下午8:19:48
 * @描述 数据转化通用工具类
 */
public class CastCommons {

	public static final String DATE = "yyyy-MM-dd";
	public static final String DATE_SLASH = "yyyy/MM/dd";
	public static final String DATE_CHINA = "yyyy年MM月dd日";
	public static final String DATE_NUMBER = "yyyyMMdd";
	public static final String TIME = "HH:mm:ss";
	public static final String TIME_CHINA = "HH时mm分ss秒";
	public static final String TIME_NUMBER = "HHmmss";
	public static final String DATE_TIME = "yyyy-MM-dd HH:mm:ss";
	public static final String DATE_TIME_SLASH = "yyyy/MM/dd HH:mm:ss";
	public static final String DATE_TIME_CHINA = "yyyy年MM月dd日 HH时mm分ss秒";
	public static final String DATE_TIME_NUMBER = "yyyyMMddHHmmss";
	public static final String MILLI_SECOND = "SSS";

	private static String dateFormatCache = CacheCommons.buildCacheName(CastCommons.class, "dateFormat");

	/**
	 * <pre>
	 * 将字符串转化 byte[]，如果无法进行转换则返回 null
	 * </pre>
	 * @param str 需转换的字符串
	 * @param encode 字符集
	 * @return byte[]
	 */
	public static byte[] stringToBytes(String str, String encode) {
		byte[] bytes = null;
		if (ValidateCommons.isNotEmpty(str)) {
			try {
				if (ValidateCommons.isEmpty(encode)) {
					bytes = str.getBytes();
				} else {
					bytes = str.getBytes(encode);
				}
			} catch (UnsupportedEncodingException e) {
				Logger.error(CastCommons.class, "转化失败", e);
			}
		}
		return bytes;
	}

	/**
	 * <pre>
	 * 将字符串转化为 byte[]，使用系统默认编码，如果无法进行转换则返回 null
	 * </pre>
	 * @param str 需转换的字符串
	 * @return byte[]
	 */
	public static byte[] stringToBytes(String str) {
		return stringToBytes(str, null);
	}

	/**
	 * <pre>
	 * 字符串转换为短整型，如果无法进行转换则返回 null
	 * </pre>
	 * @param str 需转换的字符串
	 * @return Short
	 */
	public static Short stringToShort(String str) {
		Short st = null;
		if (ValidateDataType.validateShort(str)) {
			st = Short.parseShort(str);
		}
		return st;
	}

	/**
	 * <pre>
	 * 字符串转换为整型，如果无法进行转换则返回 null
	 * </pre>
	 * @param str 需转换的字符串
	 * @return Integer
	 */
	public static Integer stringToInteger(String str) {
		Integer ir = null;
		if (ValidateDataType.validateInteger(str)) {
			ir = Integer.parseInt(str);
		}
		return ir;
	}

	/**
	 * <pre>
	 * 字符串转换为长整型，如果无法进行转换则返回 null
	 * </pre>
	 * @param str 需转换的字符串
	 * @return Long
	 */
	public static Long stringToLong(String str) {
		Long lg = null;
		if (ValidateDataType.validateLong(str)) {
			lg = Long.parseLong(str);
		}
		return lg;
	}

	/**
	 * <pre>
	 * 字符串转换为单精度浮点型，如果无法进行转换则返回 null
	 * </pre>
	 * @param str 需转换的字符串
	 * @return Float
	 */
	public static Float stringToFloat(String str) {
		Float ft = null;
		if (ValidateDataType.validateFloat(str)) {
			ft = Float.parseFloat(str);
		}
		return ft;
	}

	/**
	 * <pre>
	 * 字符串转换为双精度浮点型，如果无法进行转换则返回 null
	 * </pre>
	 * @param str 需转换的字符串
	 * @return Double
	 */
	public static Double stringToDouble(String str) {
		Double de = null;
		if (ValidateDataType.validateDouble(str)) {
			de = Double.parseDouble(str);
		}
		return de;
	}

	/**
	 * <pre>
	 * 转换为布尔值
	 * 映射（不分大小写）
	 * true：true | t | yes | y | 1
	 * false：其它值
	 * </pre>
	 * @param str 需处理字符串
	 * @return 布尔值
	 */
	public static boolean stringToBoolean(String str) {
		return stringToBoolean(str, false);
	}

	/**
	 * <pre>
	 * 转换为布尔值
	 * 映射（不分大小写）
	 * true：true | t | yes | y | 1
	 * false：false | f | no | n | 0
	 * </pre>
	 * @param str 需处理字符串
	 * @param useStrictlyMode 是否使用严格模式，严格模式下 true、false 都需要使用合规值，非严格模式下只需要 true 使用合规值，不符合 true 的值都返回 false
	 * @return 布尔值
	 */
	public static boolean stringToBoolean(String str, boolean useStrictlyMode) {
		str = StringCommons.toLowerCase(str);
		if ("true".equals(str) || "t".equals(str) || "yes".equals(str) || "y".equals(str) || "1".equals(str)) {
			return true;
		} else if (!useStrictlyMode) {
			return false;
		} else if ("false".equals(str) || "f".equals(str) || "no".equals(str) || "n".equals(str) || "0".equals(str)) {
			return false;
		} else {
			throw new RuntimeException("不合规的值，可选值（不分大小写）有：[true | t | yes | y | 1 | false | f | no | n | 0]");
		}
	}

	/**
	 * <pre>
	 * 数字类型转换为字符串，如果无法进行转换则返回 null
	 * </pre>
     * @param number 需转换的数字
     * @param format 格式化数字，统一转换后的字符串长度，长度不够在前面补零。如果传入的数字为浮点型则会在整数、小数部分分别补format长度的零
	 * @return String
	 */
	public static String numberToString(Number number, Integer format) {
		String str = null;
		if (ValidateCommons.isNotEmpty(number)) {
			// 处理大数字科学计数法
			DecimalFormat df = new DecimalFormat("#.#");
			df.setMaximumIntegerDigits(16);
			df.setMaximumFractionDigits(16);
			str = df.format(number);
			if (ValidateCommons.isNotEmpty(format, true, "0")) {
				if (Float.class.equals(number.getClass()) || Double.class.equals(number.getClass())) {
					String[] tempArray = str.split("\\.");
					String prefix = tempArray[0];
					String suffix = tempArray[1];
					for (int i = prefix.length(); i < format; i++) {
						prefix = StringCommons.merger("0", prefix);
					}
					for (int i = suffix.length(); i < format; i++) {
						suffix = StringCommons.merger(suffix, "0");
					}
					str = StringCommons.merger(prefix, ".", suffix);
				} else {
					for (int i = str.length(); i < format; i++) {
						str = "0" + str;
					}
				}
			}
		}
		return str;
	}

	/**
	 * <pre>
	 * 数字类型转换为字符串，如果无法进行转换则返回 null
	 * </pre>
     * @param number 需转换的数字
	 * @return String
	 */
	public static String numberToString(Number number) {
		return numberToString(number, 0);
	}

	/**
	 * <pre>
	 * 获取指定格式的 SimpleDateFormat
	 * SimpleDateFormat 是线程不安全的，因此使用 ThreadLocal 保证其只在一个线程中共享，从而保证线程安全
	 * </pre>
	 * @param format
	 * @return SimpleDateFormat
	 */
	public static SimpleDateFormat getSimpleDateFormat(final String format) {
		ThreadLocal<SimpleDateFormat> threadLocal = null;
		try {
			threadLocal = CacheCommons.get(dateFormatCache, format, new Callable<String, ThreadLocal<SimpleDateFormat>>() {
				@Override
				public ThreadLocal<SimpleDateFormat> call(String cacheName) throws Exception {
					return new ThreadLocal<SimpleDateFormat>() {
						@Override
						public SimpleDateFormat initialValue() {
							return new SimpleDateFormat(format);
						}
					};
				}
			});
		} catch (Exception e) {
			Logger.warn(CastCommons.class, StringCommons.merger("从缓存中获取指定格式 [", format, "] SimpleDateFormat 异常"), e);
		}
		if (ValidateCommons.isNotEmpty(threadLocal)) {
			return threadLocal.get();
		} else {
			return null;
		}
	}

	/**
	 * <pre>
	 * 字符串转换为时间，如果无法进行转换则返回 null
	 * </pre>
	 * @param str 需转换的字符串
	 * @param format 时间格式
	 * @return Date
	 */
	public static Date stringToDate(String str, String format) {
		Date date = null;
		if (ValidateDataType.validataDate(str, format)) {
			SimpleDateFormat sfd = getSimpleDateFormat(format);
			try {
				date = sfd.parse(str);
			} catch (Exception e) {
				Logger.warn(CastCommons.class, StringCommons.merger("字符串 [", str, "] 转换为指定格式 [", format, "] 时间异常"), e);
			}
		}
		return date;
	}

	/**
	 * <pre>
	 * 时间转换为字符串，如果无法进行转换则返回 null
	 * </pre>
	 * @param date 需转换的时间
	 * @param format 时间格式
	 * @return String
	 */
	public static String dateToString(Date date, String format) {
		String str = null;
		if (ValidateCommons.isNotEmpty(date)) {
			SimpleDateFormat sfd = getSimpleDateFormat(format);
			try {
				str = sfd.format(date);
			} catch (Exception e) {
				Logger.warn(CastCommons.class, StringCommons.merger("时间 [", date, "] 转换为指定格式 [", format, "] 字符串异常"), e);
			}
		}
		return str;
	}

	/**
	 * <pre>
	 * 将数据转换为指定类型
	 * </pre>
	 * @param obj 数据
	 * @param targetClass 目标类型
	 * @return 转换后的值
	 */
	public static Object to(Object obj, Class<?> targetClass) {
		String fromClassName = obj.getClass().getName();
		String targetClassName = targetClass.getName();
		// TODO 此处需要大量枚举
		if (BigDecimal.class.getName().equals(fromClassName)) {
			BigDecimal bd = (BigDecimal) obj;
			if (Double.class.getName().equals(targetClassName) || double.class.getName().equals(targetClassName)) {
				obj = bd.doubleValue();
			} else if (Float.class.getName().equals(targetClassName) || float.class.getName().equals(targetClassName)) {
				obj = bd.floatValue();
			} else if (Integer.class.getName().equals(targetClassName) || int.class.getName().equals(targetClassName)) {
				obj = bd.intValue();
			} else if (Long.class.getName().equals(targetClassName) || long.class.getName().equals(targetClassName)) {
				obj = bd.longValue();
			} else if (Short.class.getName().equals(targetClassName) || short.class.getName().equals(targetClassName)) {
				obj = bd.shortValue();
			}
		} else if (BigInteger.class.getName().equals(fromClassName)) {
			BigInteger bi = (BigInteger) obj;
			if (Double.class.getName().equals(targetClassName) || double.class.getName().equals(targetClassName)) {
				obj = bi.doubleValue();
			} else if (Float.class.getName().equals(targetClassName) || float.class.getName().equals(targetClassName)) {
				obj = bi.floatValue();
			} else if (Integer.class.getName().equals(targetClassName) || int.class.getName().equals(targetClassName)) {
				obj = bi.intValue();
			} else if (Long.class.getName().equals(targetClassName) || long.class.getName().equals(targetClassName)) {
				obj = bi.longValue();
			} else if (Short.class.getName().equals(targetClassName) || short.class.getName().equals(targetClassName)) {
				obj = bi.shortValue();
			}
		}
		return obj;
	}

	/**
	 * <pre>
	 * 将无泛型的 List 转换为具体的类型
	 * 
	 * [警告] 此转换并不能达到真正的转换，主要用于入参符合入参规范，实际传入的参数需要与泛型相匹配
	 * </pre>
	 * @param objList 需转换的 List
	 * @return 泛型处理后的 List
	 */
	public static <T> List<T> castList(List objList) {
		List<T> list = new ArrayList<T>();
		if (ValidateCommons.isNotEmpty(objList)) {
			for (Object obj : objList) {
				if (ValidateCommons.isNotEmpty(obj)) {
					list.add((T) obj);
				}
			}
		}
		return list;
	}

	/**
	 * <pre>
	 * 将无泛型的 Map 转换为具体的类型
	 * [警告] 此转换并不能达到真正的转换，主要用于入参符合入参规范，实际传入的参数需要与泛型相匹配
	 * </pre>
	 * @param objMap 需转换的 Map
	 * @return 泛型处理后的 Map
	 */
	public static <K, V> Map<K, V> castMap(Map objMap) {
		Map<K, V> map = new HashMap<K, V>();
		if (ValidateCommons.isNotEmpty(objMap)) {
			for (Object key : objMap.keySet()) {
				map.put((K) key, (V) objMap.get(key));
			}
		}
		return map;
	}

}
